package org.walkerljl.commons.image.group;

import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import org.walkerljl.commons.datetime.DateUtils;
import org.walkerljl.commons.image.group.enums.GroupCondition;
import org.walkerljl.commons.io.FileUtils;
import org.walkerljl.commons.log.Logger;
import org.walkerljl.commons.log.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * GroupConsumer
 *
 * @author lijunlin
 */
public class GroupConsumer implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(GroupConsumer.class);

    private BlockingQueue<File> taskQueue;
    private GroupCondition groupCondition;
    private String destDirectoryPath;
    private AtomicInteger index;
    private int maxQuantitiesPerDestDirectory = 100;
    private CountDownLatch finishLatch;

    private Map<String, File> destDirectoryMap;

    public GroupConsumer(BlockingQueue<File> taskQueue, GroupCondition groupCondition, String destDirectoryPath,
                         AtomicInteger index, int maxQuantitiesPerDestDirectory, Map<String, File> destDirectoryMap,
                         CountDownLatch finishLatch) {
        this.taskQueue = taskQueue;
        this.groupCondition = groupCondition;
        this.destDirectoryPath = destDirectoryPath;
        this.index = index;
        this.maxQuantitiesPerDestDirectory = maxQuantitiesPerDestDirectory;
        this.destDirectoryMap = destDirectoryMap;
        this.finishLatch = finishLatch;
    }

    @Override
    public void run() {
        File task = null;
        try {
            task = taskQueue.take();
            while (task != null) {
                run0(task);
                task = taskQueue.take();
            }

            if (LOGGER.isInfoEnabled()) {
                LOGGER.info(String.format("[%s]Task is done.",
                        Thread.currentThread().getName()));
            }
        } catch (Throwable e) {
            LOGGER.error(e);
        } finally {
            finishLatch.countDown();
        }
    }

    private void run0(File file) throws Exception {
        if (file.isFile()) {
            String baseFilePath = destDirectoryPath + File.separator + parseGroupKeyword(file);
            String tempDestDirectoryPath = baseFilePath + "_" + (index.incrementAndGet() / maxQuantitiesPerDestDirectory) + File.separator;
            File destDirectory = destDirectoryMap.get(tempDestDirectoryPath);
            if (destDirectory == null) {
                synchronized (destDirectoryPath) {
                    if (destDirectory == null) {
                        FileUtils.mkdirs(tempDestDirectoryPath);
                        destDirectory = new File(tempDestDirectoryPath);
                        destDirectoryMap.put(tempDestDirectoryPath, destDirectory);
                    }
                }
            }

            file.setLastModified(System.currentTimeMillis());
            String fileName = file.getPath();
            String newFileName = tempDestDirectoryPath + parseImageCreated(file) + fileName.substring(fileName.indexOf("."));
            file.renameTo(new File(newFileName));
            FileUtils.copy(file, destDirectory);
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info(String.format("[%s]Grouped one image %s to %s.",
                        Thread.currentThread().getName(), file.getAbsolutePath(), newFileName));
            }
        } else if (file.isDirectory()) {
            File[] subFiles = file.listFiles();
            if (subFiles == null || subFiles.length == 0) {
                return;
            }
            for (File subFile : subFiles) {
                run0(subFile);
            }
        }
    }

    private String parseGroupKeyword(File file) throws ImageProcessingException, IOException {
        String keyword = null;
        if (groupCondition == GroupCondition.TIME_YEAR) {
            keyword = DateUtils.dateFormat(parseImageCreated(file), "yyyy");
        } else if (groupCondition == GroupCondition.TIME_MONTH) {
            keyword = DateUtils.dateFormat(parseImageCreated(file), "yyyy-MM");
        } else if (groupCondition == GroupCondition.TIME_DAY) {
            keyword = DateUtils.dateFormat(parseImageCreated(file), "yyyy-MM-dd");
        }
        return keyword;
    }

    private Date parseImageCreated(File file) throws ImageProcessingException, IOException {
        Metadata metadata = ImageMetadataReader.readMetadata(file);
        ExifSubIFDDirectory directory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
        Date date = directory.getDateDigitized(TimeZone.getDefault());
        return date;
    }
}
